# -*- coding:utf-8 -*-

import xlrd
import os
import sys
import json
from common import ReadConfig
from common.Log import MyLog

# excel存放路径
_TEST_FILE_PATH = os.path.dirname(os.path.abspath(__file__)) + r'/../testFile/'


class OperationExcel:

    def __init__(self):
        """
        初始化，获取Excel名称，表索引
        """
        self.filename = ReadConfig.FILENAME
        self.sheet_id = ReadConfig.SHEET_ID
        self.book = self.open_excel()
        self.sheet = self.book.sheet_by_index(self.sheet_id)

    def open_excel(self):
        """
        打开excel并返回Book对象
        :return:
        """
        try:
            book = xlrd.open_workbook(_TEST_FILE_PATH + self.filename)
        except FileNotFoundError:
            MyLog().logger.error('---- Can not found \"' + self.filename + '\", please check config msg.')
            MyLog().logger.warning('exit...')
            sys.exit()
        return book

    def get_rows(self):
        """
        获取sheet有效行数
        :return:
        """
        return self.sheet.nrows

    def get_row_col_value(self, row, col):
        """
        获取指定行、列的值, 如果为空返回None
        :return:
        """
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.info('----- Excel rowx ' + str(row + 1) + 'colx ' + str(col + 1) + ' is empty.')
            res = None
        return res

    def get_case_name_by_row(self, row):
        """
        获取指定行用例名称, 如果为空返回None
        :param row:
        :return:
        """
        col = ReadConfig.CASE_NAME_ID
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.error('---- Excel rowx ' + str(row + 1) + ' case name is empty.')
            res = None
        return res

    def get_module_name_by_row(self, row):
        """
        获取指定行模块名称, 如果为空返回Default
        :param row:
        :return:
        """
        col = ReadConfig.MODULE_NAME_ID
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.info('----- Excel rowx ' + str(row + 1) + ' module name is empty.')
            res = 'Default'
        return res

    def get_request_method_by_row(self, row):
        """
        获取指定行请求类型, 如果为空返回None
        :param row:指定行
        :return:
        """
        col = ReadConfig.REQUEST_METHOD_ID
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.error('---- Excel rowx ' + str(row + 1) + ' request method is empty.')
            res = None
        return res

    def get_request_url_by_row(self, row):
        """
        获取指定行请求地址, 如果为空返回None
        :param row:
        :return:
        """
        col = ReadConfig.REQUEST_URL_ID
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.error('---- Excel rowx ' + str(row + 1) + ' request url is empty.')
            res = None
        return res

    def get_request_data_by_row(self, row):
        """
        以字典形式返回指定行请求数据,如果为空返回{}
        :param row:
        :return: dict:
        """
        col = ReadConfig.REQUEST_DATA_ID
        if self.empty(row, col):
            MyLog().logger.warning('-- Excel rowx ' + str(row + 1) + ' request data is empty.')
            return {}
        res = self.sheet.cell_value(row, col)
        res = self.__parse_dot(res)
        try:
            res = json.loads(res)
        except json.decoder.JSONDecodeError:
            res = eval(res)
        except not json.decoder.JSONDecodeError:
            MyLog().logger.error('---- parse rowx ' + str(row + 1) + ' request data fail, please check case ' +
                                 self.get_case_name_by_row(row) + '.')
        return res

    def get_expect_result_by_row(self, row):
        """
        以字典形式返回指定行期望结果, 如果为空返回None
        json=True表示以json对象返回，默认False
        :param row:
        :return:
        """
        col = ReadConfig.EXPECTED_RESULT_ID
        if self.empty(row, col):
            MyLog().logger.error('---- Excel rowx ' + str(row + 1) + ' expect data is empty.')
            return None
        res = self.sheet.cell_value(row, col)
        res = self.__parse_dot(res)
        try:
            res = json.loads(res)
        except json.decoder.JSONDecodeError:
            res = eval(res)
        except not json.decoder.JSONDecodeError:
            MyLog().logger.error('---- parse rowx ' + str(row + 1) + ' expect data fail, please check case ' +
                                 self.get_case_name_by_row(row) + '.')
        return res

    def get_depend_case_by_row(self, row):
        """
        以字典形式返回依赖用例, 如果为空返回None
        :param row:
        :return:
        """
        col = ReadConfig.DEPEND_CASE_ID
        if self.empty(row, col):
            return None
        res = self.sheet.cell_value(row, col)
        res = self.__parse_dot(res)
        try:
            res = json.loads(res)
        except json.decoder.JSONDecodeError:
            res = eval(res)
        except not json.decoder.JSONDecodeError:
            MyLog().logger.error('---- parse rowx ' + str(row + 1) + ' depend case fail, please check case ' +
                                 self.get_case_name_by_row(row) + '.')
        return res

    def get_middle_data(self, row):
        """
        以列表形式中间数据，空值返回None
        :param row:
        :return:
        """
        col = ReadConfig.MIDDLE_DATA
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            return None
        return res.split(',')

    def is_del_depend_data(self, row):
        """
        是否删除依赖数据
        :param row:
        :return:
        """
        return self.is_true(row, col=ReadConfig.DEL_MIDDLE)

    def get_update_request_url(self, row):
        """
        更新接口地址
        :param row:
        :return:
        """
        col = ReadConfig.UPDATE_URL
        if self.empty(row, col):
            return None
        res = self.sheet.cell_value(row, col)
        res = self.__parse_dot(res)
        try:
            res = json.loads(res)
        except json.decoder.JSONDecodeError:
            res = eval(res)
        except not json.decoder.JSONDecodeError:
            MyLog().logger.error('---- parse rowx ' + str(row + 1) + ' update url fail, please check case ' +
                                 self.get_case_name_by_row(row) + '.')
        return res

    def get_case_des_by_row(self, row):
        """
        获取指定行用例描述, 如果为空返回None
        :param row:
        :return:
        """
        col = ReadConfig.CASE_DESCRIPTION_ID
        res = self.sheet.cell_value(row, col)
        if self.empty(row, col):
            MyLog().logger.info('----- Excel rowx ' + str(row + 1) + ' case description is empty.')
            res = None
        return res

    def get_row_by_case_name(self, case_name):
        """
        通过用例名称获取用例所在行数, 如果为空返回None
        :param case_name: 用例名称
        :return:
        """
        rows = self.sheet.nrows
        res = None
        for i in range(1, rows):
            if case_name == self.get_row_col_value(i, ReadConfig.CASE_NAME_ID):
                res = i
                break
        if res is None:
            MyLog().logger.error('---- Can not found case ' + case_name + ', please check config msg.')
        return res

    def get_depend_case_name_by_row(self, row):
        """
        以列表的形式返回依赖的用例名称, 无依赖用例返回None
        :param row:
        :return:
        """
        if self.empty(row, ReadConfig.DEPEND_CASE_ID):
            return None
        depend_case = self.get_depend_case_by_row(row)
        res = []
        for key in depend_case:
            res.append(key)
        return res

    def get_case_by_row(self, row):
        """
        以字典形式返回指定行用例
        :param row:
        :return:
        """
        res = dict()
        res.update({
            'case_name': self.get_case_name_by_row(row),
            'module_name': self.get_module_name_by_row(row),
            'request_method': self.get_request_method_by_row(row),
            'request_url': self.get_request_url_by_row(row),
            'request_data': self.get_request_data_by_row(row),
            'expect_res': self.get_expect_result_by_row(row),
            'depend_case': self.get_depend_case_by_row(row),
            'middle_data': self.get_middle_data(row),
            'del_depend': self.is_del_depend_data(row),
            'update_url': self.get_update_request_url(row),
            'case_description': self.get_case_des_by_row(row)
        })
        return res

    def get_case_by_case_name(self, case_name):
        """
        通过用例名称获取用例
        :param case_name:
        :return:
        """
        row = self.get_row_by_case_name(case_name)
        return self.get_case_by_row(row)

    def is_true(self, row, col):
        """
        判断一个cell为True or False
        :param row:
        :param col:
        :return:
        """
        res = self.sheet.cell_value(row, col)
        ctype = self.sheet.cell(row, col).ctype
        if res and ctype == 4:
            return True
        elif ctype == 1 and res.lower() == 'true':
            return True
        else:
            return False

    def empty(self, row, col):
        """
        判断cell值是否为空
        :param row:
        :param col:
        :return:
        """
        # excel ctype值：0 empty,1 string, 2 number, 3 date, 4 boolean, 5 error
        res = False
        if self.sheet.cell(row, col).ctype == 0:
            res = True
        if self.sheet.cell(row, col).ctype == 1:
            res = self.sheet.cell(row, col).value.isspace()
        return res

    @staticmethod
    def __parse_dot(res=str):
        """
        解析字符串，将单引号转为双引号
        :param res:
        :return:
        """
        if '\'' in res:
            res = res.replace('\'', '\"')
        return res

    def get_all_case(self):
        """
        以列表形式返回所有用例
        :return:
        """
        all_case = []
        if ReadConfig.IS_RUN_ALL:
            rows = self.get_rows()
            for i in range(1, rows):
                all_case.append(self.get_case_by_row(i))
        else:
            case_group = ReadConfig.TEST_CASE_GROUP
            for i in range(0, len(case_group)):
                all_case.append(self.get_case_by_case_name(case_group[i]))
        return all_case

    def get_module_name_list(self):
        """
        以列表形式返回需要执行用例模块名称, 当模块名称为空时设置为Default
        :return:
        """
        module_list = []
        cases = self.get_all_case()
        for i in range(0, len(cases)):
            module_name = cases[i]['module_name']
            if module_name is None:
                module_name = 'Default'
            if module_name not in module_list:
                module_list.append(module_name)
        return module_list
